package cc.shacocloud.mirage.bean;

import cc.shacocloud.mirage.bean.exception.BeanException;
import cc.shacocloud.mirage.bean.exception.NoSuchBeanException;
import cc.shacocloud.mirage.bean.meta.BeanDescription;
import cc.shacocloud.mirage.bean.meta.BeanKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiPredicate;

/**
 * 用于存储 {@link BeanKey} 和 {@code S} 映射关系的 Map
 *
 * @param <S> 具体存储的对象，即 {@link BeanKey} 映射的对象
 * @author 思追(shaco)
 */
public interface BeanKeyMap<S> {
    
    /**
     * 添加对象
     */
    void add(@NotNull BeanKey beanKey, @NotNull S s);
    
    /**
     * 获取 {@link BeanKey} 映射的对象
     * <p>
     * 使用 {@link BeanKey#canInject(BeanKey)} 来判断返回
     *
     * @throws NoSuchBeanException 如果不存在则抛出该例外
     * @throws BeanException       如果查询失败则抛出该例外
     */
    @NotNull
    default S find(@NotNull BeanKey beanKey) throws BeanException, NoSuchBeanException {
        return Objects.requireNonNull(find(beanKey, true));
    }
    
    /**
     * 获取 {@link BeanKey} 映射的对象，基于 {@code throwEx} 判断是否抛出例外
     * <p>
     * 使用 {@link BeanKey#canInject(BeanKey)} 来判断返回
     * <p>
     * 可以和 {@link #contains(BeanKey)} 配套使用
     *
     * @throws NoSuchBeanException 如果不存在则抛出该例外
     * @throws BeanException       如果查询失败则抛出该例外
     */
    @Nullable
    S find(@NotNull BeanKey beanKey, boolean throwEx) throws BeanException, NoSuchBeanException;
    
    /**
     * 获取 {@link BeanKey} 映射的对象
     * <p>
     * 使用 {@link BeanKey#equals(Object)} 和 {@link BeanKey#hashCode()} 来判断返回
     * <p>
     * 可以和 {@link #containsKey(BeanKey)} 配套使用
     */
    @Nullable
    S get(@NotNull BeanKey beanKey);
    
    /**
     * 循环内部所有的 {@link BeanKey} 用于 {@code predicate} 判断，如果为 true 则返回
     */
    @NotNull
    Collection<BeanKey> findBeanKeyBy(BiPredicate<BeanKey, S> predicate);
    
    /**
     * 获取所有 {@link BeanKey} 和映射值
     */
    @NotNull
    Map<BeanKey, S> getAll();
    
    /**
     * 返回当前映射中 {@link BeanDescription} 的数量
     */
    int size();
    
    /**
     * 判断 {@link BeanKey} 是否在能被已经存储的进行注入，如果可以则返回 true 反正 false
     */
    boolean contains(@NotNull BeanKey beanKey);
    
    /**
     * 判断 {@link BeanKey} 是否存在
     *
     * @param beanKey 必须是内部返回的 {@link BeanKey}，否则结果可能不准确
     */
    boolean containsKey(@NotNull BeanKey beanKey);
    
    /**
     * 查询匹配的所有 bean，并返回{@link BeanKey}。
     * <p>
     * 这些键可用于获取实际的 Bean 数据
     */
    @NotNull
    Collection<BeanKey> findBeanKeys(@NotNull BeanKey beanKey);
    
    /**
     * 基于注解查询匹配的所有 bean，并返回 {@link BeanKey}。
     * <p>
     * 这些键可用于获取实际的 Bean 数据
     */
    @NotNull
    Collection<BeanKey> findBeanKeysByAnnotation(@NotNull Class<? extends Annotation> annotation);
    
    /**
     * 删除 {@link BeanKey} 的对应的映射
     */
    void remove(@NotNull BeanKey beanKey);
    
    /**
     * 删除 {@link BeanKey}
     */
    void removeKey(@NotNull BeanKey beanKey);
    
}
